﻿#include "NearFieldDataGenerator.h"
#include <vtkTable.h>
#include <vtkDataSet.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkStructuredGrid.h>
#include <vtkTableToStructuredGrid.h>
#include <vtkStructuredGridWriter.h>
#include "CommonFunction.h"
#include <unordered_set>
#include <QDebug>

namespace pst
{

    NearFieldDataGenerator::NearFieldDataGenerator(QObject* parent)
        : QObject(parent)
        , m_useLog(false)
        , m_useNormalize(false)
        , m_originalTable(nullptr)
        , m_resultTable(nullptr)
        , m_resultDataSet(vtkSmartPointer<vtkStructuredGrid>::New())
        , m_logFactory(10)
        , m_setTableExtends{ 0,0,0 }
        , m_inverserXYZ{ false }
        , m_useComputedExtecnd{ true }
    {
    }

    NearFieldDataGenerator::~NearFieldDataGenerator()
    {
    }
    void NearFieldDataGenerator::setInputData(vtkTable* table)
    {
        m_originalTable = table;
    }
    void NearFieldDataGenerator::setLogTheData(bool useLog)
    {
        m_useLog = useLog;
    }
    bool NearFieldDataGenerator::getLogTheData()
    {
        return m_useLog;
    }
    void NearFieldDataGenerator::setNormalizeTheData(bool useNormalize)
    {
        m_useNormalize = useNormalize;
    }
    bool NearFieldDataGenerator::getNormalizeTheData()
    {
        return m_useNormalize;
    }
    void NearFieldDataGenerator::setTableExtends(int xMax, int yMax, int zmax)
    {
        m_setTableExtends[0] = xMax;
        m_setTableExtends[1] = yMax;
        m_setTableExtends[2] = zmax;
    }

    void NearFieldDataGenerator::setUseComputedExtend(bool use)
    {
        m_useComputedExtecnd = use;
    }

    bool NearFieldDataGenerator::getUseComputedExtend()
    {
        return m_useComputedExtecnd;
    }

    void NearFieldDataGenerator::inverserXYZ(bool inverse)
    {
        m_inverserXYZ = inverse;
    }

    bool NearFieldDataGenerator::update()
    {
        if (m_originalTable == nullptr)
        {
            return false;
        }
        //先归一化
        vtkSmartPointer<vtkTable> normalizedTable;
        if (m_useNormalize)
        {
            normalizedTable = vtkSmartPointer<vtkTable>::New();
            normalizeTheTable(m_originalTable, normalizedTable);
        }
        else
        {
            normalizedTable = m_originalTable;
        }

        //再取对数
        double colorOffeset{ 0 };
        if (m_useLog)
        {
            m_resultTable = vtkSmartPointer<vtkTable>::New();
            logTheTable(normalizedTable, m_resultTable, colorOffeset);
        }
        else
        {
            m_resultTable = normalizedTable;
        }


        if (m_useComputedExtecnd)
        {
            computeTableExtends();
            transformTableToStructuredGrid(m_resultTable, m_resultDataSet, m_computedTableExtends[0] - 1, m_computedTableExtends[1] - 1, m_computedTableExtends[2] - 1, m_inverserXYZ);
        }
        else
        {
            transformTableToStructuredGrid(m_resultTable, m_resultDataSet, m_setTableExtends[0], m_setTableExtends[1], m_setTableExtends[2], m_inverserXYZ);
        }
        m_resultDataSet->GetPointData()->SetActiveAttribute(0, vtkDataSetAttributes::AttributeTypes::SCALARS);
        return true;
    }

    vtkDataSet* NearFieldDataGenerator::getOutputData()
    {
        return m_resultDataSet;
    }

    void NearFieldDataGenerator::SetLogFactory(double factory)
    {
        m_logFactory = factory;
    }

    void NearFieldDataGenerator::transformTableToStructuredGrid(vtkTable* inputTable,
        vtkStructuredGrid* outStructuredGrid, int xMax, int yMax, int zMax, bool reverseXYZ)
    {
        vtkNew<vtkTableToStructuredGrid> tableToSGFilter;
        tableToSGFilter->SetInputData(inputTable);
        if (reverseXYZ)
        {
            tableToSGFilter->SetXColumn(inputTable->GetColumn(2)->GetName());
            tableToSGFilter->SetYColumn(inputTable->GetColumn(1)->GetName());
            tableToSGFilter->SetZColumn(inputTable->GetColumn(0)->GetName());
            tableToSGFilter->SetWholeExtent(0, zMax, 0, yMax, 0, xMax);
        }
        else
        {
            tableToSGFilter->SetXColumn(inputTable->GetColumn(0)->GetName());
            tableToSGFilter->SetYColumn(inputTable->GetColumn(1)->GetName());
            tableToSGFilter->SetZColumn(inputTable->GetColumn(2)->GetName());
            tableToSGFilter->SetWholeExtent(0, xMax, 0, yMax, 0, zMax);
        }


        tableToSGFilter->Update();

        //vtkNew< vtkStructuredGridWriter> writer;
        //writer->SetInputConnection(tableToSGFilter->GetOutputPort());
        //writer->SetFileName("nearFieldStruc.vtk");
        //writer->Write();

        outStructuredGrid->DeepCopy(tableToSGFilter->GetOutput());
    }
    void NearFieldDataGenerator::logTheTable(vtkTable* inputTable,
        vtkTable* outputTable, double& logedMinimalValue)
    {
        //auto colsNum = inputTable->GetNumberOfColumns();
        outputTable->DeepCopy(inputTable);
        auto valueArray = outputTable->GetColumn(3); //值列
        if (valueArray == nullptr)
        {
            return;
        }
        auto rowNum = valueArray->GetNumberOfTuples();
        for (int i = 0; i < rowNum; ++i)
        {
            auto value = valueArray->GetVariantValue(i).ToDouble();
            valueArray->SetVariantValue(i, m_logFactory * std::log10(value));
        }
    }

    void NearFieldDataGenerator::normalizeTheTable(vtkTable* inputTable,
        vtkTable* outputTable)
    {
        outputTable->DeepCopy(inputTable);
        auto valueArray = vtkDoubleArray::SafeDownCast(outputTable->GetColumn(3)); //值列
        if (valueArray == nullptr)
        {
            return;
        }

        auto maxValue = valueArray->GetValueRange()[1];

        auto rowNum = valueArray->GetNumberOfTuples();
        for (int i = 0; i < rowNum; ++i)
        {
            auto value = valueArray->GetVariantValue(i).ToDouble();
            valueArray->SetVariantValue(i, value / maxValue);
        }
    }

    void NearFieldDataGenerator::computeTableExtends()
    {
        if (m_originalTable == nullptr)
        {
            return;
        }
        vtkIdType numberOfColumns = m_originalTable->GetNumberOfColumns();
        if (numberOfColumns < 3)
        {
            return;
        }

        for (vtkIdType col = 0; col < numberOfColumns; ++col)
        {
            vtkDataArray* columnData = vtkDataArray::SafeDownCast(m_originalTable->GetColumn(col));

            if (columnData && columnData->GetNumberOfValues() > 0)
            {
                std::unordered_set<double> uniqueValues;
                for (vtkIdType row = 0; row < columnData->GetNumberOfValues(); ++row)
                {
                    double value = columnData->GetComponent(row, 0);
                    uniqueValues.insert(value);
                }
                if (col < 3)
                {
                    m_computedTableExtends[col] = uniqueValues.size();
                }
                qDebug() << "Column " << col << " has " << uniqueValues.size() << " unique values.";
            }
            else
            {
                qDebug() << "Column " << col << " has no data.";
            }
        }

    }
}
